import random
import time
import math
import win32api  # 仅保留用于获取屏幕尺寸和光标位置
from ctypes import CDLL, c_char_p

# ↓↓↓↓↓↓↓↓↓ 调用ghub键鼠驱动 ↓↓↓↓↓↓↓↓↓
class ghub_device:
    info = None
    
    def __init__(self):
        try:
            self.gm = CDLL(r'./ghub_device_GHUB.dll')  # ghubdlldir
            self.gm_ok = self.gm.device_open()
            self.gm.key_down.argtypes = [c_char_p]
            self.gm.key_up.argtypes = [c_char_p]
            if not self.gm_ok:
                self.info = '未安装ghub或者lgs驱动!!!'
            else:
                self.info = '驱动初始化成功!'
        except FileNotFoundError:
            self.info = '重要键鼠文件缺失'
            self.gm_ok = 0
    
    def _mouse_event(self, fun, *args):
        if self.gm_ok:
            try:
                if hasattr(self.gm, fun):
                    return getattr(self.gm, fun)(*args)
                else:
                    return None
            except (NameError, OSError):
                self.info = '键鼠调用严重错误!!!'
    
    def mouse_R(self, x, y):
        return self._mouse_event('moveR', int(x), int(y))
    
    def mouse_To(self, x, y):
        return self._mouse_event('moveTo', int(x), int(y))
    
    def mouse_down(self, key=1):
        return self._mouse_event('mouse_down', int(key))
    
    def mouse_up(self, key=1):
        return self._mouse_event('mouse_up', int(key))
    
    def scroll(self, num=1):
        return self._mouse_event('scroll', int(num))
    
    def key_down(self, key):
        return self._mouse_event('key_down', key.encode('utf-8'))

    def key_up(self, key):
        return self._mouse_event('key_up', key.encode('utf-8'))

    def device_close(self):
        return self._mouse_event('device_close')


# 初始化GHUB驱动
gm = ghub_device()
if not gm.gm_ok:
    raise SystemExit(f"驱动初始化失败: {gm.info}")

def cubic_bezier(p0, p1, p2, p3, num_points):
    """生成三次贝塞尔曲线路径点"""
    points = []
    for t in (i / (num_points - 1) for i in range(num_points)):
        x = (1 - t)**3 * p0[0] + 3 * (1 - t)**2 * t * p1[0] + 3 * (1 - t) * t**2 * p2[0] + t**3 * p3[0]
        y = (1 - t)**3 * p0[1] + 3 * (1 - t)**2 * t * p1[1] + 3 * (1 - t) * t**2 * p2[1] + t**3 * p3[1]
        points.append((x, y))
    return points

def generate_control_points(start, end, screen_w, screen_h):
    """生成带边界约束的贝塞尔曲线控制点"""
    dx = end[0] - start[0]
    dy = end[1] - start[1]
    
    # 计算垂直方向向量
    perp_dx = -dy
    perp_dy = dx
    
    # 处理零向量情况
    length = math.hypot(perp_dx, perp_dy)
    if length == 0:
        return (start, start, end, end)
    
    # 归一化垂直向量
    perp_dx /= length
    perp_dy /= length
    
    # 动态调整曲线强度
    max_intensity = min(screen_w, screen_h) * 0.15
    curve_intensity = math.hypot(dx, dy) * random.uniform(0.1, 0.3)
    curve_intensity = min(curve_intensity, max_intensity)
    
    # 边界约束函数
    def clamp(value, min_val, max_val):
        return max(min_val, min(value, max_val))
    
    # 生成控制点
    ctrl1 = (
        clamp(start[0] + dx * 0.25 + perp_dx * curve_intensity, 0, screen_w),
        clamp(start[1] + dy * 0.25 + perp_dy * curve_intensity, 0, screen_h)
    )
    ctrl2 = (
        clamp(start[0] + dx * 0.75 - perp_dx * curve_intensity, 0, screen_w),
        clamp(start[1] + dy * 0.75 - perp_dy * curve_intensity, 0, screen_h)
    )
    return ctrl1, ctrl2

def human_mouse_move(end_x, end_y, vtime, num_points):
    """模拟人类鼠标移动核心函数（GHUB驱动版）"""
    # 获取屏幕尺寸
    screen_w = win32api.GetSystemMetrics(0) - 1
    screen_h = win32api.GetSystemMetrics(1) - 1

    try:
        start_x, start_y = win32api.GetCursorPos()
    except win32api.error:
        raise Exception("无法获取初始鼠标位置")
    
    # 约束目标位置
    end_x = max(0, min(end_x, screen_w))
    end_y = max(0, min(end_y, screen_h))
    
    # 生成控制点和路径
    start = (start_x, start_y)
    end = (end_x, end_y)
    ctrl1, ctrl2 = generate_control_points(start, end, screen_w, screen_h)
    points = cubic_bezier(start, ctrl1, ctrl2, end, num_points)
    
    # 添加随机扰动
    points = [
        (
            x + random.uniform(-0.5, 0.5),
            y + random.uniform(-0.5, 0.5)
        ) for x, y in points
    ]
    
    # 边界约束路径点
    points = [
        (max(0, min(x, screen_w)), 
        max(0, min(y, screen_h)))
        for x, y in points
    ]
    
    base_delay = vtime / len(points)
    MAX_STEP = 3  # 单次移动最大步长
    
    # 执行移动
    for i, (target_x, target_y) in enumerate(points):
        try:
            current_x, current_y = win32api.GetCursorPos()
        except win32api.error:
            break
        
        # 最终点使用绝对移动
        if i == len(points) - 1:
            gm.mouse_To(int(end_x), int(end_y))  # 确保强制转换为整数
            time.sleep(base_delay * 1.5)  # 增加最终校正延时
            break
        
        # 计算总移动距离时添加强制校正
        total_dx = target_x - current_x
        total_dy = target_y - current_y
        
        # 修改步长计算方式，避免整数截断误差
        steps = max(1, int(math.ceil(math.hypot(total_dx, total_dy) / MAX_STEP)))
        step_dx = total_dx / steps
        step_dy = total_dy / steps
        
        # 分步相对移动时保留浮点精度
        for step in range(steps):
            dx = step_dx * (step + 1) - step_dx * step
            dy = step_dy * (step + 1) - step_dy * step
            gm.mouse_R(int(round(dx)), int(round(dy)))  # 添加四舍五入
            time.sleep(base_delay / steps * random.uniform(0.9, 1.1))
    
    # 强制最终位置校正（新增二次校验）
    for _ in range(3):  # 最多尝试3次校正
        current_pos = win32api.GetCursorPos()
        if (current_pos[0], current_pos[1]) != (end_x, end_y):
            gm.mouse_To(int(end_x), int(end_y))
            time.sleep(0.05)



def get_valid_coordinate(prompt, max_value):
    """获取有效坐标输入"""
    while True:
        try:
            value = int(input(prompt))
            if 0 <= value <= max_value:
                return value
            print(f"输入超出范围 (0-{max_value})，请重新输入")
        except ValueError:
            print("请输入有效的整数")

if __name__ == "__main__":
    if not gm.gm_ok:
        print("驱动初始化失败:", gm.info)
        exit()
    
    # 获取屏幕尺寸
    screen_w = win32api.GetSystemMetrics(0) - 1
    screen_h = win32api.GetSystemMetrics(1) - 1
    
    print(f"当前屏幕尺寸：{screen_w}x{screen_h}")
    print("请输入目标坐标：")
    
    # 获取用户输入
    target_x = 100
    target_y = 900
    vtime = 0.2 #移动时间
    num_points = 500  # 根据实际需要调整
    
    # 执行移动
    try:
        print(f"开始移动到 ({target_x}, {target_y})")
        human_mouse_move(target_x, target_y, vtime, num_points)
        final_pos = win32api.GetCursorPos()
        print(f"移动完成，最终位置: {final_pos}")
    except Exception as e:
        print(f"移动过程中出现错误: {str(e)}")